#pragma once

#include <windows.h>
#include <string>
#include <cstdint>
#include <stdexcept>

namespace NahidaProject {

	template<typename R, typename... Args> class __declspec(dllexport) DynamicLinkedLibraryLoader {
	public:
		DynamicLinkedLibraryLoader(HMODULE handleOfModule, const char* functionName) : func(nullptr), handleOfModule(handleOfModule), functionName(functionName) {

		}

		DynamicLinkedLibraryLoader(HMODULE handleOfModule, std::string functionName) : func(nullptr), handleOfModule(handleOfModule) {
			functionName = functionName.c_str();
		}

		R operator()(Args... args) {
			if (!func) {
				func = reinterpret_cast<R(*)(Args...)>(GetProcAddress(handleOfModule, functionName));
				if (!func) {
					throw std::runtime_error("Failed to load function: " + std::string(functionName));
				}
			}
			return func(std::forward<Args>(args)...);
		}

		static void FreeDynamicLinkedLibraryLoader(HMODULE& dll) {
			if (dll) {
				FreeLibrary(dll);
				dll = nullptr;
			}
		}

	private:
		R(*func)(Args...);
		HMODULE handleOfModule;
		const char* functionName;
	};
}
